package com.moss.cloud.base.biz.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.moss.cloud.base.api.model.from.ApprovalFrom;
import com.moss.cloud.base.api.model.from.BaseFrom;
import com.moss.cloud.base.api.model.from.FlowBusinessFrom;
import com.moss.cloud.base.api.model.from.TaskFrom;
import com.moss.cloud.base.api.model.param.FlowBusinessParam;
import com.moss.cloud.base.api.model.vo.FlowBusinessVO;
import com.moss.cloud.base.api.model.vo.FlowTaskVO;
import com.moss.cloud.base.biz.mapper.FlowBusinessMapper;
import com.moss.cloud.base.biz.model.FlowBusiness;
import com.moss.cloud.base.biz.model.FlowModel;
import com.moss.cloud.base.biz.model.FlowTask;
import com.moss.cloud.base.biz.service.IFlowBusinessService;
import com.moss.cloud.base.biz.service.IFlowModelService;
import com.moss.cloud.base.biz.service.IFlowTaskService;
import com.moss.cloud.base.biz.service.ISysUserService;
import com.moss.cloud.base.biz.utils.DataProUtil;
import com.moss.cloud.common.base.model.po.SysUser;
import com.moss.cloud.common.base.utils.PageUtil;
import com.moss.cloud.common.core.exception.SystemErrorType;
import com.moss.cloud.common.core.utils.BooleanHandel;
import com.moss.cloud.common.core.utils.UserContextHolder;
import com.moss.cloud.common.flow.enums.Target;
import com.moss.cloud.common.flow.executor.TaskExecutor;
import com.moss.cloud.common.flow.model.NodeTask;
import com.moss.cloud.common.flow.parser.TaskParser;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 业务流程业务实现
 *
 * @author 瑾年
 * @date 2024-03-06
 */
@Slf4j
@Service
public class FlowBusinessServiceImpl extends ServiceImpl<FlowBusinessMapper, FlowBusiness> implements IFlowBusinessService {
    private final IFlowModelService flowModelService;
    private final IFlowTaskService flowTaskService;
    private final ISysUserService sysUserService;

    public FlowBusinessServiceImpl(IFlowModelService flowModelService, IFlowTaskService flowTaskService,
                                   ISysUserService sysUserService) {
        this.flowModelService = flowModelService;
        this.flowTaskService = flowTaskService;
        this.sysUserService = sysUserService;
    }

    /**
     * 分页查询
     *
     * @param param
     * @return
     */
    @Override
    public IPage<FlowBusinessVO> page(FlowBusinessParam param) {
        Page<FlowBusiness> page = PageUtil.createPage(param.getCurrent(), param.getSize());
        return baseMapper.flowBusinessPage(page, UserContextHolder.getTenantId(), param, UserContextHolder.getUserId());
    }

    /**
     * 新增
     *
     * @param from
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveFlowBusiness(FlowBusinessFrom from) {
        FlowBusiness flowBusiness = new FlowBusiness();
        BeanUtils.copyProperties(from, flowBusiness);
        flowBusiness.setTenantId(UserContextHolder.getTenantId());
        this.save(flowBusiness);
        ((FlowBusinessServiceImpl) AopContext.currentProxy()).saveFlowTask(from);
        this.startFlowTask(flowBusiness.getId());
        return Boolean.TRUE;
    }

    /**
     * 批量保存任务
     *
     * @param from
     */
    @Transactional(rollbackFor = Exception.class)
    public void saveFlowTask(FlowBusinessFrom from) {
        List<FlowTask> flowTasks = from.getNodeTasks().stream().map(item -> {
            FlowTask flowTask = new FlowTask();
            BeanUtils.copyProperties(item, flowTask);
            flowTask.setApprovalUsers(item.getHeadUsers());
            flowTask.setCcUsers(item.getCcToUsers());
            return flowTask;
        }).collect(Collectors.toList());
        flowTaskService.saveBatchFlowTask(flowTasks);
    }

    /**
     * 更新
     *
     * @param from
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean update(FlowBusinessFrom from) {
        BooleanHandel.trueThrow(Objects.isNull(from.getId())).throwMessage(SystemErrorType.PRIMARY_KEY);
        FlowBusiness flowBusiness = this.getById(from.getId());
        this.checkData(flowBusiness);
        FlowBusiness model = new FlowBusiness();
        BeanUtils.copyProperties(from, model);
        this.updateById(model);
        flowTaskService.removeBatchFlowTask(from.getId());
        ((FlowBusinessServiceImpl) AopContext.currentProxy()).saveFlowTask(from);
        this.startFlowTask(flowBusiness.getId());
        return Boolean.TRUE;
    }


    /**
     * 删除
     *
     * @param baseFrom
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean remove(BaseFrom baseFrom) {
        FlowBusiness flowBusiness = this.getById(baseFrom.getId());
        this.checkData(flowBusiness);
        boolean flag = this.removeById(baseFrom.getId());
        return flag ? flowTaskService.removeBatchFlowTask(baseFrom.getId()) : Boolean.FALSE;
    }

    /**
     * 验证数据所属权
     *
     * @param flowBusiness
     */
    private void checkData(FlowBusiness flowBusiness) {
        BooleanHandel.trueThrow(Objects.isNull(flowBusiness)).throwMessage(SystemErrorType.DATE_EMPTY);
        BooleanHandel.trueThrow(!flowBusiness.getTenantId().equals(UserContextHolder.getTenantId())).throwMessage(SystemErrorType.NOT_BELONG_TENANT);
    }

    /**
     * 详情
     *
     * @param baseFrom
     * @return
     */
    @Override
    public FlowBusinessVO detail(BaseFrom baseFrom) {
        FlowBusinessVO flowBusinessVO = baseMapper.flowBusinessDetail(UserContextHolder.getTenantId(), baseFrom.getId(), UserContextHolder.getUserId());
        List<FlowTask> flowTasks = flowTaskService.list(new QueryWrapper<FlowTask>().lambda().eq(FlowTask::getBusId, baseFrom.getId()));
        SysUser user = sysUserService.getById(flowBusinessVO.getUserId());
        List<FlowTaskVO> flowTaskVOS = new ArrayList<>();
        flowTaskVOS.add(DataProUtil.addApplyFlowUser(user.getName(), user.getId()));
        List<FlowTaskVO> taskVOS = CollectionUtils.isNotEmpty(flowTasks) ? flowTasks.stream().map(item -> {
            FlowTaskVO flowTaskVO = new FlowTaskVO();
            BeanUtils.copyProperties(item, flowTaskVO);
            flowTaskVO.setApprovalUsers(this.approvalUsers(Arrays.stream(item.getApprovalUsers().split(",")).map(Long::valueOf)
                    .collect(Collectors.toList())));
            flowTaskVO.setCcUsers(this.approvalUsers(Arrays.stream(item.getCcUsers().split(",")).map(Long::valueOf)
                    .collect(Collectors.toList())));
            return flowTaskVO;
        }).collect(Collectors.toList()) : Collections.emptyList();
        flowTaskVOS.addAll(taskVOS);
        flowBusinessVO.setNodeTasks(flowTaskVOS);
        return flowBusinessVO;
    }

    /**
     * 不携带任务节点的详情
     *
     * @param id
     * @param tenantId
     * @param userId
     * @return
     */
    private FlowBusinessVO flowBusiness(Long id, Long tenantId, Long userId) {
        return baseMapper.flowBusinessDetail(tenantId, id, userId);
    }

    /**
     * 获取任务节点
     *
     * @param from
     * @return
     */
    @Override
    public List<FlowTaskVO> nodeTasks(TaskFrom from) {
        FlowModel flowModel = flowModelService.getById(from.getModelId());
        List<NodeTask> nodeTasks = new ArrayList<>();
        // 把申请人添加到节点中
        SysUser user = sysUserService.getById(UserContextHolder.getUserId());
        nodeTasks.add(DataProUtil.addApplyUser(user.getName(), user.getId()));
        List<NodeTask> tasks = TaskParser.taskNodes(flowModel.getFlowData(), from.getFlowForm());
        nodeTasks.addAll(tasks);
        return CollectionUtils.isNotEmpty(nodeTasks) ? nodeTasks.stream().map(item -> {
            System.out.println(item.getCcToUsers());
            FlowTaskVO flowTaskVO = new FlowTaskVO();
            BeanUtils.copyProperties(item, flowTaskVO);
            flowTaskVO.setApprovalUsers(this.approvalUsers(item.getHeadUsers()));
            flowTaskVO.setCcUsers(this.approvalUsers(item.getCcToUsers()));
            return flowTaskVO;
        }).collect(Collectors.toList()) : Collections.emptyList();
    }

    /**
     * 审批人抄送人信息
     *
     * @param userIds
     * @return
     */
    private List<FlowTaskVO.ApprovalUser> approvalUsers(List<Long> userIds) {
        List<SysUser> sysUsers = sysUserService.list(new QueryWrapper<SysUser>().lambda().in(SysUser::getId, userIds));
        return CollectionUtils.isNotEmpty(sysUsers) ? sysUsers.stream().map(x -> {
            FlowTaskVO.ApprovalUser approvalUser = new FlowTaskVO.ApprovalUser();
            BeanUtils.copyProperties(x, approvalUser);
            return approvalUser;
        }).collect(Collectors.toList()) : Collections.emptyList();
    }

    private void startFlowTask(Long busId) {
        List<FlowTask> flowTasks = flowTaskService.list(new QueryWrapper<FlowTask>().lambda().eq(FlowTask::getBusId, busId));
        FlowTask flowTask = flowTasks.stream().findFirst().orElse(null);
        BooleanHandel.isTrue(Objects.nonNull(flowTask)).trueHandle(() -> {
            NodeTask nodeTask = this.convertNodeTask(flowTask, flowTask.getStatus());
            TaskExecutor.process(nodeTask);
        });
    }

    /**
     * 流程审批
     *
     * @param approvalFrom
     * @return
     */
    @Override
    public boolean approval(ApprovalFrom approvalFrom) {
        FlowTask flowTask = flowTaskService.getById(approvalFrom.getId());
        BooleanHandel.trueThrow(Objects.isNull(flowTask)).throwMessage(SystemErrorType.DATE_EMPTY);
        NodeTask nodeTask = this.convertNodeTask(flowTask, approvalFrom.getStatus());
        TaskExecutor.process(nodeTask);
        this.nextTask(flowTask, approvalFrom.getStatus());
        return Boolean.TRUE;
    }

    /**
     * 转换成NodeTask对象
     *
     * @param flowTask
     * @param status
     * @return
     */
    private NodeTask convertNodeTask(FlowTask flowTask, Integer status) {
        NodeTask nodeTask = new NodeTask();
        BeanUtils.copyProperties(flowTask, nodeTask);
        nodeTask.setHeadUsers(Arrays.stream(flowTask.getApprovalUsers().split(",")).map(Long::valueOf)
                .collect(Collectors.toList()));
        nodeTask.setCcToUsers(Arrays.stream(flowTask.getCcUsers().split(",")).map(Long::valueOf)
                .collect(Collectors.toList()));
        nodeTask.setStatus(status);
        return nodeTask;
    }

    /**
     * 下一个任务
     *
     * @param flowTask
     */
    public void nextTask(FlowTask flowTask, Integer status) {
        FlowTask nextTask = flowTaskService.getOne(new QueryWrapper<FlowTask>().lambda()
                .eq(FlowTask::getTaskId, flowTask.getTarget())
                .eq(FlowTask::getBusId, flowTask.getBusId()));
        BooleanHandel.trueThrow(Objects.isNull(nextTask)).throwMessage(SystemErrorType.DATE_EMPTY);
        BooleanHandel.isTureOrFalse(Target.END.getType().equals(nextTask.getTarget())).trueOrFalseHandle(() ->
                ((FlowBusinessServiceImpl) AopContext.currentProxy()).finish(flowTask, status), () ->
                this.nodeProcess(nextTask, status));
    }

    /**
     * 下一个节点过程
     *
     * @param nextTask
     * @param status
     */
    public void nodeProcess(FlowTask nextTask, Integer status) {
        // 根据模型配置和status状态判断如果是其中一个节点不通过直接结束的话调用finish方法即可
        NodeTask nodeTask = this.convertNodeTask(nextTask, nextTask.getStatus());
        TaskExecutor.process(nodeTask);
    }

    /**
     * 流程结束
     *
     * @param flowTask
     * @param status
     */
    @Transactional(rollbackFor = Exception.class)
    public void finish(FlowTask flowTask, Integer status) {
        // 四种结束模式 先获取模型的配置再根据status判断
        // 1流程模型配置的有一个节点审批不通过直接结束流程
        // 2少数服从多数，多数通过流程通过
        // 3指定人通过流程通过
        // 4全部通过
        FlowBusinessVO business = this.flowBusiness(UserContextHolder.getTenantId(), flowTask.getId(),
                UserContextHolder.getUserId());
        BooleanHandel.trueThrow(Objects.isNull(business)).throwMessage(SystemErrorType.DATE_EMPTY);
        FlowBusiness flowBusiness = new FlowBusiness();
        flowBusiness.setId(flowTask.getBusId());
        flowBusiness.setFlowStatus(status);
        log.info("任务结束后发布一个任务流程完结的通知信息:{}", business.getFlowModelName());
        this.updateById(flowBusiness);
    }

}
